package owndemo;
import owndemo.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/*
进行测试
 */
public class test {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, IOException, NoSuchMethodException, InvocationTargetException {
        //1、根据类的全路径加载创建类的模板对象
        //类模板中包含了Field属性和定义的Methond对象
        Class clazz = Class.forName("owndemo.Teacher");  //此处只写类名有时候识别不了，尽量全路径
        //2、调用类的无参构造器创建对象
        Object object =  clazz.newInstance();
        System.out.println(object);


        //一、属性的反射测试


        //3、属性赋值、获取公共的属性getField
        ((Teacher)object).name="小李";
        Field ageFiled = clazz.getField("age");

        //4、private测试只要在本类的属性就能取到,不受访问控制修饰符影响private、public
        Field salaryFiled = clazz.getDeclaredField("salary");
        salaryFiled.setAccessible(true);  //私有的属性需要设置
        salaryFiled.set(object,200);
        System.out.println("老师的工资是"+salaryFiled.get(object));

        //二、通过反射，类实现了哪些接口

        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);  //这样我们就可以找到Teacher类的父类，person类的全路径


        Class[] interfaces = clazz.getInterfaces();
        for (int i = 0; i <interfaces.length ; i++) {
            System.out.println("实现的接口"+interfaces[i]);
        }


        //三、创建对象的4种方法

            //1、常规使用，软编码
            Class clazz1= Class.forName("owndemo.Teacher");

            //2、最简单，硬编码
            Class clazz2=Teacher.class;

            System.out.println(clazz1==clazz2);

            //3.比较灵活、硬编码
            Class clazz3=new Teacher().getClass();

            System.out.println(clazz2==clazz3);

            //4、比较复杂，先获取类的加载器对象，再手工加载类、软编码
            new test().test1();

    }
    public  void test1() throws ClassNotFoundException, IOException, IllegalAccessException, NoSuchFieldException, InstantiationException, NoSuchMethodException, InvocationTargetException {
            //4、比较复杂，先获取类的加载器对象，再手工加载类、软编码(此处不能卸载main函数中)
            ClassLoader classLoader=this.getClass().getClassLoader();
            Class class4=classLoader.loadClass("owndemo.Teacher");

            System.out.println("——————————————————分割线——————————————————————————");

            //四、通过反射获取类加载器
            ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
            System.out.println(systemClassLoader);
            ClassLoader parent = systemClassLoader.getParent();
            System.out.println(parent);
            ClassLoader parent1 = parent.getParent();
            System.out.println(parent1);
            System.out.println("——————————————————分割线1——————————————————————————");
             //引导加载类记载核心类
            System.out.println(""+Object.class.getClassLoader());
            System.out.println(""+Person.class.getClassLoader());

            new test().test2();
            new test().test3();
            new test().test4();

            new test().test5();
    }
    public void  test2() throws IOException {
        //加载器读取资源文件的当前目录，src目录
        //src目录就是classoath中的，可以直接从jar包中读取资源文件
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("owndemo/test.properties");
        Properties properties = new Properties();
        properties.load(resourceAsStream);
        System.out.println(properties.getProperty("key"));


    }

    //五、通过反射获取类的方法、并实现方法
    public void  test3() throws NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        System.out.println("————————————分割test3——————————————————");
        Class clazz=Teacher.class;
        Object object=clazz.newInstance();
        Field field=clazz.getDeclaredField("name");
        field.setAccessible(true);
        field.set(object,"小花");
        System.out.println(object);

        //调用方法(从类的对象中获取方法对象，getMethon会获或者从父类集成的所有的公共方式)
        Method eatMethon = clazz.getMethod("eat", String.class);
        //通过方法对象简介调用自己
        Object retuValue = eatMethon.invoke(object, "面包");
        System.out.println("返回值"+retuValue);
        
        //调用eat的重载函数
        Method eatTwoMethon = clazz.getMethod("eat", String.class, int.class);
        Object retuValue1 = eatTwoMethon.invoke(object, "稀饭", 1);


        Method toStringMethon=clazz.getMethod("toString");
        Object retValue2=toStringMethon.invoke(object);
        System.out.println(retValue2);

        //获取Teacher的所有方法，包括私有方法
        Method concatMethon = clazz.getDeclaredMethod("concat", int.class, double.class, char.class, boolean.class);
        concatMethon.setAccessible(true);
        Object returnValue3 = concatMethon.invoke(object, 100, 3.14, '你', true);
        System.out.println(returnValue3);




    }
    public  void test4() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //六、获取父类的私有方法
        System.out.println("———————————————————分割Test4———————————————————");
        Class clazz1=Teacher.class;
        Object object=clazz1.newInstance();
        Method superPrivatetest = clazz1.getSuperclass().getDeclaredMethod("privateTest");
        superPrivatetest.setAccessible(true);
        superPrivatetest.invoke(object);
    }
    //七、通过反射获取一个类的构造器，属性、方法
    public void test5() throws ClassNotFoundException {
        System.out.println("———————————————分割线test5———————————————————");
        String className="java.util.HashMap";
        Class clazz=Class.forName(className);
        //获取所有的构造器
        Constructor[] constructors=clazz.getDeclaredConstructors();
        for (int i = 0; i < constructors.length; i++) {
            System.out.println(constructors[i]);
        }

        //获取本类中声明的所有的属性
        Field[] filed=clazz.getDeclaredFields();
        for (int i = 0; i < filed.length; i++) {
            System.out.println(filed[i]);
        }


    }
}
